using System.Text;
using System.Text.Json;
using System.Data.Common;
using Oracle.ManagedDataAccess.Client;
using Microsoft.Data.SqlClient;

namespace Lzfy_His_Service.Middleware
{
    /// <summary>
    /// 增强的数据库日志记录中间件 - 捕获所有数据库相关异常
    /// </summary>
    public class EnhancedDatabaseLoggingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<EnhancedDatabaseLoggingMiddleware> _logger;
        private readonly IConfiguration _configuration;

        public EnhancedDatabaseLoggingMiddleware(
            RequestDelegate next,
            ILogger<EnhancedDatabaseLoggingMiddleware> logger,
            IConfiguration configuration)
        {
            _next = next;
            _logger = logger;
            _configuration = configuration;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            var startTime = DateTime.UtcNow;
            var requestId = Guid.NewGuid().ToString("N");
            
            // 添加请求ID到上下文
            context.Items["RequestId"] = requestId;
            context.Request.Headers["X-Request-ID"] = requestId;

            // 记录请求开始
            await LogRequestStartAsync(context, requestId);

            // 捕获响应
            var originalResponseBodyStream = context.Response.Body;
            using var responseBodyStream = new MemoryStream();
            context.Response.Body = responseBodyStream;

            try
            {
                await _next(context);

                // 如果响应是错误，记录详细信息
                if (context.Response.StatusCode >= 400)
                {
                    await LogErrorResponseAsync(context, responseBodyStream, startTime, requestId);
                }
                else
                {
                    await LogSuccessfulResponseAsync(context, responseBodyStream, startTime, requestId);
                }
            }
            catch (Exception ex)
            {
                // 捕获所有异常，特别是数据库相关异常
                await HandleExceptionAsync(context, ex, startTime, requestId);
                throw; // 重新抛出异常让全局异常处理器处理
            }
            finally
            {
                // 恢复响应流
                responseBodyStream.Seek(0, SeekOrigin.Begin);
                await responseBodyStream.CopyToAsync(originalResponseBodyStream);
                context.Response.Body = originalResponseBodyStream;
            }
        }

        /// <summary>
        /// 记录请求开始
        /// </summary>
        private Task LogRequestStartAsync(HttpContext context, string requestId)
        {
            var request = context.Request;
            var logData = new
            {
                RequestId = requestId,
                Method = request.Method,
                Path = request.Path,
                QueryString = request.QueryString.ToString(),
                UserAgent = request.Headers["User-Agent"].ToString(),
                ClientIP = context.Connection.RemoteIpAddress?.ToString(),
                Timestamp = DateTime.UtcNow
            };

            _logger.LogInformation("HTTP请求开始: {RequestData}", JsonSerializer.Serialize(logData));
            return Task.CompletedTask;
        }

        /// <summary>
        /// 记录成功响应
        /// </summary>
        private async Task LogSuccessfulResponseAsync(HttpContext context, MemoryStream responseStream, DateTime startTime, string requestId)
        {
            var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
            
            responseStream.Seek(0, SeekOrigin.Begin);
            var responseBody = await new StreamReader(responseStream).ReadToEndAsync();
            responseStream.Seek(0, SeekOrigin.Begin);

            // 检查响应体是否包含数据库相关错误
            if (ContainsDatabaseError(responseBody))
            {
                var logData = new
                {
                    RequestId = requestId,
                    StatusCode = context.Response.StatusCode,
                    ElapsedMs = elapsedMs,
                    ResponseBody = responseBody,
                    Timestamp = DateTime.UtcNow
                };

                _logger.LogWarning("响应包含数据库错误: {ResponseData}", JsonSerializer.Serialize(logData));
            }
            else if (elapsedMs > 10000) // 响应时间超过10秒
            {
                _logger.LogWarning("请求响应缓慢: {RequestId} 耗时 {ElapsedMs}ms", requestId, elapsedMs);
            }
        }

        /// <summary>
        /// 记录错误响应
        /// </summary>
        private async Task LogErrorResponseAsync(HttpContext context, MemoryStream responseStream, DateTime startTime, string requestId)
        {
            var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
            
            responseStream.Seek(0, SeekOrigin.Begin);
            var responseBody = await new StreamReader(responseStream).ReadToEndAsync();
            responseStream.Seek(0, SeekOrigin.Begin);

            var logData = new
            {
                RequestId = requestId,
                StatusCode = context.Response.StatusCode,
                ElapsedMs = elapsedMs,
                ResponseBody = responseBody,
                DatabaseError = ContainsDatabaseError(responseBody),
                Timestamp = DateTime.UtcNow
            };

            _logger.LogError("HTTP请求错误: {ResponseData}", JsonSerializer.Serialize(logData));
        }

        /// <summary>
        /// 处理异常
        /// </summary>
        private Task HandleExceptionAsync(HttpContext context, Exception exception, DateTime startTime, string requestId)
        {
            var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
            
            var logData = new
            {
                RequestId = requestId,
                ExceptionType = exception.GetType().Name,
                ExceptionMessage = exception.Message,
                ExceptionStackTrace = exception.StackTrace,
                ElapsedMs = elapsedMs,
                IsDatabaseException = IsDatabaseException(exception),
                DatabaseErrorCode = GetDatabaseErrorCode(exception),
                Timestamp = DateTime.UtcNow
            };

            _logger.LogError(exception, "未捕获异常: {ExceptionData}", JsonSerializer.Serialize(logData));

            // 如果是数据库超时异常，额外记录
            if (IsDatabaseTimeoutException(exception))
            {
                _logger.LogCritical("数据库连接超时异常: {RequestId} - {ErrorMessage}", requestId, exception.Message);
            }

            return Task.CompletedTask;
        }

        /// <summary>
        /// 检查是否包含数据库错误
        /// </summary>
        private bool ContainsDatabaseError(string responseBody)
        {
            if (string.IsNullOrEmpty(responseBody))
                return false;

            var lowerBody = responseBody.ToLower();
            
            // 更精确的数据库错误检测，避免误报
            return (lowerBody.Contains("timeout") && lowerBody.Contains("database")) ||
                   (lowerBody.Contains("connection") && lowerBody.Contains("failed")) ||
                   lowerBody.Contains("ora-") ||
                   lowerBody.Contains("sqlstate") ||
                   lowerBody.Contains("database error") ||
                   (lowerBody.Contains("error") && (lowerBody.Contains("database") || lowerBody.Contains("oracle") || lowerBody.Contains("sql")));
        }

        /// <summary>
        /// 判断是否为数据库异常
        /// </summary>
        private bool IsDatabaseException(Exception exception)
        {
            return exception is OracleException ||
                   exception is SqlException ||
                   exception is DbException ||
                   exception is TimeoutException;
        }

        /// <summary>
        /// 判断是否为数据库超时异常
        /// </summary>
        private bool IsDatabaseTimeoutException(Exception exception)
        {
            if (exception is OracleException oracleEx)
            {
                return oracleEx.Number == 12170 || // ORA-12170: TNS:Connect timeout occurred
                       oracleEx.Number == 12535 || // ORA-12535: TNS:operation timed out
                       oracleEx.Number == 12560 || // ORA-12560: TNS:protocol adapter error
                       oracleEx.Message.Contains("timeout", StringComparison.OrdinalIgnoreCase);
            }

            if (exception is SqlException sqlEx)
            {
                return sqlEx.Number == 2 || // 无法连接到SQL Server
                       sqlEx.Number == 53 || // 无法建立连接
                       sqlEx.Message.Contains("timeout", StringComparison.OrdinalIgnoreCase);
            }

            return exception is TimeoutException ||
                   exception.Message.Contains("timeout", StringComparison.OrdinalIgnoreCase);
        }

        /// <summary>
        /// 获取数据库错误码
        /// </summary>
        private string GetDatabaseErrorCode(Exception exception)
        {
            return exception switch
            {
                OracleException oracleEx => oracleEx.Number.ToString(),
                SqlException sqlEx => sqlEx.Number.ToString(),
                _ => exception.HResult.ToString()
            };
        }
    }

    /// <summary>
    /// 中间件扩展方法
    /// </summary>
    public static class EnhancedDatabaseLoggingMiddlewareExtensions
    {
        public static IApplicationBuilder UseEnhancedDatabaseLogging(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<EnhancedDatabaseLoggingMiddleware>();
        }
    }
}